﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ScrewTurn.Wiki.PluginFramework;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Reflection;

namespace bokkiecorp.stw.admonitionplugin
{
    public class Admonition : IFormatterProviderV30
    {
        // Kindly contributed by Jens Felsner
        private static readonly ComponentInformation info = new ComponentInformation("Admonition Plugin", "BokkieCorp", "1.0.0.0", "http://www.babberich.info", "http://www.screwturn.eu/");

        private IHostV30 _host = null;
        private string stwAdmonitionFolder = "/admonitionresources/";
        IFilesStorageProviderV30 filesStorageProvider = null;
        private string[] types = { "warning", "caution", "note" };

        // variables to store info from the configuration
        private string _tableStyle = "background-color: #DDDDFF; border-top: solid thin #A0A0FF; border-bottom: solid thin #A0A0FF; margin-top: 5px; margin-bottom: 5px;";
        private string _iconColumnStyle = "vertical-align: top";
        private string _textColumnStyle = "vertical-align: top";
        private int _imageSize = 32;            // not yet configurable

        #region IFormatterProviderV30 Members

        public bool PerformPhase1
        {
            get { return false; }
        }

        public bool PerformPhase2
        {
            get { return true; }
        }

        public bool PerformPhase3
        {
            get { return false; }
        }

        public int ExecutionPriority
        {
            get { return 50; }
        }

        public string Format(string raw, ContextInformation context, FormattingPhase phase)
        {
            string sOutput = raw;
            // process default supported admonitions
            sOutput = processAdmonition("warning", sOutput);
            sOutput = processAdmonition("caution", sOutput);
            sOutput = processAdmonition("note", sOutput);

            // process custom admonitions
            sOutput = processCustomAdmonition(sOutput);

            return sOutput;
        }

        public string PrepareTitle(string title, ContextInformation context)
        {
            return title;
        }

        #endregion

        #region IProviderV30 Members

        public void Init(IHostV30 host, string config)
        {
            this._host = host;

            if (config == null)
                processConfig("");
            else
                processConfig(config);

            filesStorageProvider = GetDefaultFilesStorageProvider();
            // create the folder for the admonition icons if it doesn't exist yet
            if (!DirectoryExists(filesStorageProvider, stwAdmonitionFolder))
            {
                filesStorageProvider.CreateDirectory("/", stwAdmonitionFolder.Trim('/'));
            }

            // store the image for each admonition type if it doesn't exist already in STW
            for (int i = 0; i < types.Length; i++)
            {
                if (!FileExists(filesStorageProvider, stwAdmonitionFolder, types[i] + "-32.png"))
                {
                    filesStorageProvider.StoreFile(stwAdmonitionFolder + types[i] + "-32.png", Assembly.GetExecutingAssembly().GetManifestResourceStream("bokkiecorp.stw.admonitionplugin.resources." + types[i] + "-32.png"), true);
                }
            } // for (int i = 0; i < types.Length; i++)

            // dummy image in case the requested image is not available
            if (!FileExists(filesStorageProvider, stwAdmonitionFolder, "noimg.png"))
            {
                filesStorageProvider.StoreFile(stwAdmonitionFolder + "noimg.png", Assembly.GetExecutingAssembly().GetManifestResourceStream("bokkiecorp.stw.admonitionplugin.resources.noimg.png"), true);
            }

    
        }

        public void Shutdown()
        {
            
        }

        public ComponentInformation Information
        {
            get { return info; }
        }

        public string ConfigHelpHtml
        {
            get { return null; }
        }

        #endregion

        private string processAdmonition(string sType, string sContent)
        {
            // check for existence if required icon ==> replace if image not available
            if (!FileExists(filesStorageProvider, stwAdmonitionFolder, sType + "-" + _imageSize.ToString() + ".png"))
            {
                _host.LogEntry("No image available for type '" + sType + "' and image size " + _imageSize.ToString(), LogEntryType.Warning, null, this);
                sType = "noimg";
            }
            // create image URL
            string sImageUrl = buildImageUrl(sType);

            // replage tags with a table
            Regex reAdmonition = new Regex("<[ ]*"+ sType + "[ ]*>(?<content>.*?)<[ ]*/[ ]*" + sType + "[ ]*>", RegexOptions.Compiled | RegexOptions.IgnoreCase);

            return reAdmonition.Replace(sContent, "<table  style=\"" + _tableStyle + "\" width=\"100%\"><tr><td style=\"" + _iconColumnStyle + "\" width=\"50\"><img src=\"" + sImageUrl + "\" /></td><td style=\"" + _textColumnStyle + "\">${content}</td></tr></table>");
        }

        private string processCustomAdmonition(string sContent)
        {
            // Define regular expression to identify the custom admonitions
            Regex reAdmonition = new Regex("<admonition type=\"(?<type>.*)\">(?<content>.*)</admonition>", RegexOptions.Compiled | RegexOptions.IgnoreCase);

            // replace the occurrences of the regular expressions
            return reAdmonition.Replace(sContent, new MatchEvaluator(delegate(Match oMatch)
                {
                    string sType = oMatch.Groups["type"].Success ? oMatch.Groups["type"].Value : "noimg";
                    // check for existence if required icon ==> replace if image not available
                    if (!FileExists(filesStorageProvider, stwAdmonitionFolder, sType + "-" + _imageSize.ToString() + ".png"))
                    {
                        _host.LogEntry("No image available for type '" + sType + "' and image size " + _imageSize.ToString(), LogEntryType.Warning, null, this);
                        sType = "noimg";
                    }
                    string sAdmonitionText = oMatch.Groups["content"].Success ? oMatch.Groups["content"].Value : "<span style=\"color:red\">Admonition text not specified</span>";
                    string sImageUrl = buildImageUrl(sType);
                    return(buildTable(sAdmonitionText, sImageUrl));
                }));
            
        }

        #region helperfunctions
        private IFilesStorageProviderV30 GetDefaultFilesStorageProvider()
        {
            string defaultFilesStorageProviderName = _host.GetSettingValue(SettingName.DefaultFilesStorageProvider);
            return _host.GetFilesStorageProviders(true).First(p => p.GetType().FullName == defaultFilesStorageProviderName);
        }

        private bool DirectoryExists(IFilesStorageProviderV30 filesStorageProvider, string directoryName)
        {
            string[] directoryList = filesStorageProvider.ListDirectories("/");
            foreach (string dir in directoryList)
            {
                if (dir == directoryName.Trim()) return true;
            }
            return false;
        }

        private bool FileExists(IFilesStorageProviderV30 filesStorageProvider, string directory, string fileName)
        {
            string[] filesList = filesStorageProvider.ListFiles(directory);
            foreach (string file in filesList)
            {
                if (file == directory + fileName) return true;
            }
            return false;
        }

        /// <summary>
        /// Processes the configuration string
        /// </summary>
        /// <param name="config">The configuration string</param>
        private void processConfig(string config)
        {
            // table style
            Regex reTableStyle = new Regex("ts=(?<style>.*)\r\n", RegexOptions.IgnoreCase);
            Match tsMatch = reTableStyle.Match(config);
            _tableStyle = tsMatch.Groups["style"].Success ? tsMatch.Groups["style"].Value.Replace('\"', '\'') : _tableStyle;
            _host.LogEntry("Admonition table style: " + _tableStyle, LogEntryType.General, null, this);

            // icon column style
            Regex reIconColumnStyle = new Regex("ics=(?<style>.*)\r\n", RegexOptions.IgnoreCase);
            Match icsMatch = reIconColumnStyle.Match(config);
            _iconColumnStyle = icsMatch.Groups["style"].Success ? icsMatch.Groups["style"].Value.Replace('\"', '\'') : _iconColumnStyle;
            _host.LogEntry("Admonition icon column style: " + _iconColumnStyle, LogEntryType.General, null, this);

            // text column style
            Regex reTextColumnStyle = new Regex("tcs=(?<style>.*)\r\n", RegexOptions.IgnoreCase);
            Match tcsMatch = reTextColumnStyle.Match(config);
            _textColumnStyle = tcsMatch.Groups["style"].Success ? tcsMatch.Groups["style"].Value.Replace('\"', '\'') : _textColumnStyle;
            _host.LogEntry("Admonition text column style: " + _textColumnStyle, LogEntryType.General, null, this);
        }

        /// <summary>
        /// Creates an url to the image that corresponds with an admonition type
        /// </summary>
        /// <param name="sType">The admonition type</param>
        /// <returns>The URL to the image, based on the STW 'GetFile.aspx' page</returns>
        private string buildImageUrl(string sType)
        {
            if(sType == "noimg")
                return("GetFile.aspx?file=" + stwAdmonitionFolder + sType + ".png");
            else
                return ("GetFile.aspx?file=" + stwAdmonitionFolder + sType + "-" + _imageSize.ToString() + ".png");
        }

        /// <summary>
        /// Renders the admonition as a table
        /// </summary>
        /// <param name="sAdmonitionText">The admonition text</param>
        /// <param name="sImageUrl">The url to the icon that corresponds with the admonition type</param>
        /// <returns>The HTML string</returns>
        private string buildTable(string sAdmonitionText, string sImageUrl)
        {
            return("<table  style=\"" + _tableStyle + "\" width=\"100%\"><tr><td style=\"" + _iconColumnStyle + "\" width=\"50\"><img src=\"" + sImageUrl + "\" /></td><td style=\"" + _textColumnStyle + "\">" + sAdmonitionText + "</td></tr></table>");
        }
        #endregion helperfunctions
    }
}
